home *** CD-ROM | disk | FTP | other *** search
/ Aminet 41 / Aminet 41 (2001)(Schatztruhe)[!][Feb 2001].iso / Aminet / dev / c / libiconv_src.lha / src / iconv.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-07  |  13.7 KB  |  459 lines

  1. /* Copyright (C) 1999-2000 Free Software Foundation, Inc.
  2.    This file is part of the GNU ICONV Library.
  3.  
  4.    The GNU ICONV Library is free software; you can redistribute it and/or
  5.    modify it under the terms of the GNU Library General Public License as
  6.    published by the Free Software Foundation; either version 2 of the
  7.    License, or (at your option) any later version.
  8.  
  9.    The GNU ICONV Library is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.    Library General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU Library General Public
  15.    License along with the GNU ICONV Library; see the file COPYING.LIB.  If not,
  16.    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17.    Boston, MA 02111-1307, USA.  */
  18.  
  19. #include <iconv.h>
  20.  
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include "config.h"
  24.  
  25. /*
  26.  * Consider those system dependent encodings that are needed for the
  27.  * current system.
  28.  */
  29. #ifdef _AIX
  30. #define USE_AIX
  31. #endif
  32.  
  33. /*
  34.  * Converters.
  35.  */
  36. #include "converters.h"
  37.  
  38. /*
  39.  * Transliteration tables.
  40.  */
  41. #include "cjk_variants.h"
  42. #include "translit.h"
  43.  
  44. /*
  45.  * Table of all supported encodings.
  46.  */
  47. struct encoding {
  48.   struct mbtowc_funcs ifuncs; /* conversion multibyte -> unicode */
  49.   struct wctomb_funcs ofuncs; /* conversion unicode -> multibyte */
  50.   int oflags;                 /* flags for unicode -> multibyte conversion */
  51. };
  52. enum {
  53. #define DEFENCODING(xxx_names,xxx,xxx_ifuncs,xxx_ofuncs1,xxx_ofuncs2) \
  54.   ei_##xxx ,
  55. #include "encodings.def"
  56. #ifdef USE_AIX
  57. #include "encodings_aix.def"
  58. #endif
  59. #undef DEFENCODING
  60. ei_for_broken_compilers_that_dont_like_trailing_commas
  61. };
  62. #include "flags.h"
  63. static struct encoding const all_encodings[] = {
  64. #define DEFENCODING(xxx_names,xxx,xxx_ifuncs,xxx_ofuncs1,xxx_ofuncs2) \
  65.   { xxx_ifuncs, xxx_ofuncs1,xxx_ofuncs2, ei_##xxx##_oflags },
  66. #include "encodings.def"
  67. #ifdef USE_AIX
  68. #include "encodings_aix.def"
  69. #endif
  70. #undef DEFENCODING
  71. };
  72.  
  73. /*
  74.  * Alias lookup function.
  75.  * Defines
  76.  *   struct alias { const char* name; unsigned int encoding_index; };
  77.  *   const struct alias * aliases_lookup (const char *str, unsigned int len);
  78.  *   #define MAX_WORD_LENGTH ...
  79.  */
  80. #include "aliases.h"
  81.  
  82. /*
  83.  * System dependent alias lookup function.
  84.  * Defines
  85.  *   const struct alias * aliases2_lookup (const char *str);
  86.  */
  87. #if defined(USE_AIX) /* || ... */
  88. static struct alias sysdep_aliases[] = {
  89. #ifdef USE_AIX
  90. #include "aliases_aix.h"
  91. #endif
  92. };
  93. #ifdef __GNUC__
  94. __inline
  95. #endif
  96. const struct alias *
  97. aliases2_lookup (register const char *str)
  98. {
  99.   struct alias * ptr;
  100.   unsigned int count;
  101.   for (ptr = sysdep_aliases, count = sizeof(sysdep_aliases)/sizeof(sysdep_aliases[0]); count > 0; ptr++, count--)
  102.     if (!strcmp(str,ptr->name))
  103.       return ptr;
  104.   return NULL;
  105. }
  106. #else
  107. #define aliases2_lookup(str)  NULL
  108. #endif
  109.  
  110. #if 0
  111. /* Like !strcasecmp, except that the both strings can be assumed to be ASCII
  112.    and the first string can be assumed to be in uppercase. */
  113. static int strequal (const char* str1, const char* str2)
  114. {
  115.   unsigned char c1;
  116.   unsigned char c2;
  117.   for (;;) {
  118.     c1 = * (unsigned char *) str1++;
  119.     c2 = * (unsigned char *) str2++;
  120.     if (c1 == 0)
  121.       break;
  122.     if (c2 >= 'a' && c2 <= 'z')
  123.       c2 -= 'a'-'A';
  124.     if (c1 != c2)
  125.       break;
  126.   }
  127.   return (c1 == c2);
  128. }
  129. #endif
  130.  
  131. iconv_t iconv_open (const char* tocode, const char* fromcode)
  132. {
  133.   struct conv_struct * cd = (struct conv_struct *) malloc(sizeof(struct conv_struct));
  134.   char buf[MAX_WORD_LENGTH+1];
  135.   const char* cp;
  136.   char* bp;
  137.   const struct alias * ap;
  138.   unsigned int count;
  139.  
  140.   if (cd == NULL) {
  141.     errno = ENOMEM;
  142.     return (iconv_t)(-1);
  143.   }
  144.   /* Before calling aliases_lookup, convert the input string to upper case,
  145.    * and check whether it's entirely ASCII (we call gperf with option "-7"
  146.    * to achieve a smaller table) and non-empty. If it's not entirely ASCII,
  147.    * or if it's too long, it is not a valid encoding name.
  148.    */
  149.   /* Search tocode in the table. */
  150.   for (cp = tocode, bp = buf, count = MAX_WORD_LENGTH+1; ; cp++, bp++) {
  151.     unsigned char c = * (unsigned char *) cp;
  152.     if (c >= 0x80)
  153.       goto invalid;
  154.     if (c >= 'a' && c <= 'z')
  155.       c -= 'a'-'A';
  156.     *bp = c;
  157.     if (c == '\0')
  158.       break;
  159.     if (--count == 0)
  160.       goto invalid;
  161.   }
  162.   ap = aliases_lookup(buf,bp-buf);
  163.   if (ap == NULL) {
  164.     ap = aliases2_lookup(buf);
  165.     if (ap == NULL)
  166.       goto invalid;
  167.   }
  168.   cd->oindex = ap->encoding_index;
  169.   cd->ofuncs = all_encodings[ap->encoding_index].ofuncs;
  170.   cd->oflags = all_encodings[ap->encoding_index].oflags;
  171.   /* Search fromcode in the table. */
  172.   for (cp = fromcode, bp = buf, count = MAX_WORD_LENGTH+1; ; cp++, bp++) {
  173.     unsigned char c = * (unsigned char *) cp;
  174.     if (c >= 0x80)
  175.       goto invalid;
  176.     if (c >= 'a' && c <= 'z')
  177.       c -= 'a'-'A';
  178.     *bp = c;
  179.     if (c == '\0')
  180.       break;
  181.     if (--count == 0)
  182.       goto invalid;
  183.   }
  184.   ap = aliases_lookup(buf,bp-buf);
  185.   if (ap == NULL) {
  186.     ap = aliases2_lookup(buf);
  187.     if (ap == NULL)
  188.       goto invalid;
  189.   }
  190.   cd->iindex = ap->encoding_index;
  191.   cd->ifuncs = all_encodings[ap->encoding_index].ifuncs;
  192.   /* Initialize the states. */
  193.   memset(&cd->istate,'\0',sizeof(state_t));
  194.   memset(&cd->ostate,'\0',sizeof(state_t));
  195.   /* Initialize the operation flags. */
  196.   cd->transliterate = 1;
  197.   /* Done. */
  198.   return (iconv_t)cd;
  199. invalid:
  200.   errno = EINVAL;
  201.   return (iconv_t)(-1);
  202. }
  203.  
  204. size_t iconv (iconv_t icd,
  205.               ICONV_CONST char* * inbuf, size_t *inbytesleft,
  206.               char* * outbuf, size_t *outbytesleft)
  207. {
  208.   conv_t cd = (conv_t) icd;
  209.   if (inbuf == NULL || *inbuf == NULL) {
  210.     if (outbuf == NULL || *outbuf == NULL) {
  211.       /* Reset the states. */
  212.       memset(&cd->istate,'\0',sizeof(state_t));
  213.       memset(&cd->ostate,'\0',sizeof(state_t));
  214.       return 0;
  215.     } else {
  216.       if (cd->ofuncs.xxx_reset) {
  217.         int outcount =
  218.           cd->ofuncs.xxx_reset(cd, (unsigned char *) *outbuf, *outbytesleft);
  219.         if (outcount < 0) {
  220.           errno = E2BIG;
  221.           return -1;
  222.         }
  223.         *outbuf += outcount; *outbytesleft -= outcount;
  224.       }
  225.       memset(&cd->istate,'\0',sizeof(state_t));
  226.       memset(&cd->ostate,'\0',sizeof(state_t));
  227.       return 0;
  228.     }
  229.   } else {
  230.     size_t result = 0;
  231.     const unsigned char* inptr = (const unsigned char*) *inbuf;
  232.     size_t inleft = *inbytesleft;
  233.     unsigned char* outptr = (unsigned char*) *outbuf;
  234.     size_t outleft = *outbytesleft;
  235.     while (inleft > 0) {
  236.       wchar_t wc;
  237.       int incount;
  238.       int outcount;
  239.       incount = cd->ifuncs.xxx_mbtowc(cd,&wc,inptr,inleft);
  240.       if (incount <= 0) {
  241.         if (incount == 0) {
  242.           /* Case 1: invalid input */
  243.           errno = EILSEQ;
  244.           result = -1;
  245.           break;
  246.         }
  247.         if (incount == -1) {
  248.           /* Case 2: not enough bytes available to detect anything */
  249.           errno = EINVAL;
  250.           result = -1;
  251.           break;
  252.         }
  253.         /* Case 3: k bytes read, but only a shift sequence */
  254.         incount = -1-incount;
  255.       } else {
  256.         /* Case 4: k bytes read, making up a wide character */
  257.         if (outleft == 0) {
  258.           errno = E2BIG;
  259.           result = -1;
  260.           break;
  261.         }
  262.         outcount = cd->ofuncs.xxx_wctomb(cd,outptr,wc,outleft);
  263.         if (outcount != 0)
  264.           goto outcount_ok;
  265.         /* Try transliteration. */
  266.         result++;
  267.         if (cd->transliterate) {
  268.           if (cd->oflags & HAVE_HANGUL_JAMO) {
  269.             /* Decompose Hangul into Jamo. Use double-width Jamo (contained
  270.                in all Korean encodings and ISO-2022-JP-2), not half-width Jamo
  271.                (contained in Unicode only). */
  272.             wchar_t buf[3];
  273.             int ret = johab_hangul_decompose(cd,buf,wc);
  274.             if (ret != RET_ILSEQ) {
  275.               /* we know 1 <= ret <= 3 */
  276.               state_t backup_state = cd->ostate;
  277.               unsigned char* backup_outptr = outptr;
  278.               size_t backup_outleft = outleft;
  279.               int i, sub_outcount;
  280.               for (i = 0; i < ret; i++) {
  281.                 if (outleft == 0) {
  282.                   sub_outcount = RET_TOOSMALL;
  283.                   goto johab_hangul_failed;
  284.                 }
  285.                 sub_outcount = cd->ofuncs.xxx_wctomb(cd,outptr,buf[i],outleft);
  286.                 if (sub_outcount <= 0)
  287.                   goto johab_hangul_failed;
  288.                 if (!(sub_outcount <= outleft)) abort();
  289.                 outptr += sub_outcount; outleft -= sub_outcount;
  290.               }
  291.               goto char_done;
  292.             johab_hangul_failed:
  293.               cd->ostate = backup_state;
  294.               outptr = backup_outptr;
  295.               outleft = backup_outleft;
  296.               if (sub_outcount < 0) {
  297.                 errno = E2BIG;
  298.                 result = -1;
  299.                 break;
  300.               }
  301.             }
  302.           }
  303.           {
  304.             /* Try to use a variant, but postfix it with
  305.                U+303E IDEOGRAPHIC VARIATION INDICATOR
  306.                (cf. Ken Lunde's "CJKV information processing", p. 188). */
  307.             int indx = -1;
  308.             if (wc == 0x3006)
  309.               indx = 0;
  310.             else if (wc == 0x30f6)
  311.               indx = 1;
  312.             else if (wc >= 0x4e00 && wc < 0xa000)
  313.               indx = cjk_variants_indx[wc-0x4e00];
  314.             if (indx >= 0) {
  315.               for (;; indx++) {
  316.                 wchar_t buf[2];
  317.                 unsigned short variant = cjk_variants[indx];
  318.                 unsigned short last = variant & 0x8000;
  319.                 variant &= 0x7fff;
  320.                 variant += 0x3000;
  321.                 buf[0] = variant; buf[1] = 0x303e;
  322.                 {
  323.                   state_t backup_state = cd->ostate;
  324.                   unsigned char* backup_outptr = outptr;
  325.                   size_t backup_outleft = outleft;
  326.                   int i, sub_outcount;
  327.                   for (i = 0; i < 2; i++) {
  328.                     if (outleft == 0) {
  329.                       sub_outcount = RET_TOOSMALL;
  330.                       goto variant_failed;
  331.                     }
  332.                     sub_outcount = cd->ofuncs.xxx_wctomb(cd,outptr,buf[i],outleft);
  333.                     if (sub_outcount <= 0)
  334.                       goto variant_failed;
  335.                     if (!(sub_outcount <= outleft)) abort();
  336.                     outptr += sub_outcount; outleft -= sub_outcount;
  337.                   }
  338.                   goto char_done;
  339.                 variant_failed:
  340.                   cd->ostate = backup_state;
  341.                   outptr = backup_outptr;
  342.                   outleft = backup_outleft;
  343.                   if (sub_outcount < 0) {
  344.                     errno = E2BIG;
  345.                     result = -1;
  346.                     break;
  347.                   }
  348.                 }
  349.                 if (last)
  350.                   break;
  351.               }
  352.             }
  353.           }
  354.           if (wc >= 0x2018 && wc <= 0x201a) {
  355.             /* Special case for quotation marks 0x2018, 0x2019, 0x201a */
  356.             wchar_t substitute =
  357.               (cd->oflags & HAVE_QUOTATION_MARKS
  358.                ? (wc == 0x201a ? 0x2018 : wc)
  359.                : (cd->oflags & HAVE_ACCENTS
  360.                   ? (wc==0x2019 ? 0x00b4 : 0x0060) /* use accents */
  361.                   : 0x0027 /* use apostrophe */
  362.               )  );
  363.             outcount = cd->ofuncs.xxx_wctomb(cd,outptr,substitute,outleft);
  364.             if (outcount != 0)
  365.               goto outcount_ok;
  366.           }
  367.           {
  368.             /* Use the transliteration table. */
  369.             int indx = translit_index(wc);
  370.             if (indx >= 0) {
  371.               const unsigned char * cp = &translit_data[indx];
  372.               unsigned int num = *cp++;
  373.               state_t backup_state = cd->ostate;
  374.               unsigned char* backup_outptr = outptr;
  375.               size_t backup_outleft = outleft;
  376.               unsigned int i;
  377.               int sub_outcount;
  378.               for (i = 0; i < num; i++) {
  379.                 if (outleft == 0) {
  380.                   sub_outcount = RET_TOOSMALL;
  381.                   goto translit_failed;
  382.                 }
  383.                 sub_outcount = cd->ofuncs.xxx_wctomb(cd,outptr,cp[i],outleft);
  384.                 if (sub_outcount <= 0)
  385.                   goto translit_failed;
  386.                 if (!(sub_outcount <= outleft)) abort();
  387.                 outptr += sub_outcount; outleft -= sub_outcount;
  388.               }
  389.               goto char_done;
  390.             translit_failed:
  391.               cd->ostate = backup_state;
  392.               outptr = backup_outptr;
  393.               outleft = backup_outleft;
  394.               if (sub_outcount < 0) {
  395.                 errno = E2BIG;
  396.                 result = -1;
  397.                 break;
  398.               }
  399.             }
  400.           }
  401.         }
  402.         outcount = cd->ofuncs.xxx_wctomb(cd,outptr,0xFFFD,outleft);
  403.         if (outcount != 0)
  404.           goto outcount_ok;
  405.         errno = EILSEQ;
  406.         result = -1;
  407.         break;
  408.       outcount_ok:
  409.         if (outcount < 0) {
  410.           errno = E2BIG;
  411.           result = -1;
  412.           break;
  413.         }
  414.         if (!(outcount <= outleft)) abort();
  415.         outptr += outcount; outleft -= outcount;
  416.       char_done:
  417.         ;
  418.       }
  419.       if (!(incount <= inleft)) abort();
  420.       inptr += incount; inleft -= incount;
  421.     }
  422.     *inbuf = (ICONV_CONST char*) inptr;
  423.     *inbytesleft = inleft;
  424.     *outbuf = (char*) outptr;
  425.     *outbytesleft = outleft;
  426.     return result;
  427.   }
  428. }
  429.  
  430. int iconv_close (iconv_t icd)
  431. {
  432.   conv_t cd = (conv_t) icd;
  433.   free(cd);
  434.   return 0;
  435. }
  436.  
  437. #ifndef LIBICONV_PLUG
  438.  
  439. int iconvctl (iconv_t icd, int request, void* argument)
  440. {
  441.   conv_t cd = (conv_t) icd;
  442.   switch (request) {
  443.     case ICONV_TRIVIALP:
  444.       *(int *)argument = (cd->iindex == cd->oindex ? 1 : 0);
  445.       return 0;
  446.     case ICONV_GET_TRANSLITERATE:
  447.       *(int *)argument = cd->transliterate;
  448.       return 0;
  449.     case ICONV_SET_TRANSLITERATE:
  450.       cd->transliterate = (*(const int *)argument ? 1 : 0);
  451.       return 0;
  452.     default:
  453.       errno = EINVAL;
  454.       return -1;
  455.   }
  456. }
  457.  
  458. #endif
  459.